/*
 *  AAttrList.cpp
 *  libavid
 *
 *  Created by Peter on 23.02.12.
 *  Copyright 2012 __MyCompanyName__. All rights reserved.
 *
 */

#include "AAttrList.h"
#include "AStream.h"
#include "AObjDoc.h"

#include <sstream>
#include <iostream>

A_IMPLEMENT_CLASS( 'ATTR', AAttrList, AObject );

AAttrList::AttrItem* AAttrList::findItem( const std::string& attrName ) const
{
	AttrMap::const_iterator it = _items.find( attrName );

	if( it == _items.end() )
		return nullptr;

	return it->second;
}

std::string AAttrList::getAttrAsString( const std::string& attrName ) const
{
	AttrItem* item = findItem( attrName );

	if( !item )
		return "<n/a>";

	return getAttrAsString( *item );
}

std::string AAttrList::getAttrAsString( const AttrItem& item ) const
{
	switch( item._type )
	{
		case kOMFNullAttribute:
			return "<null>";
		case kOMFIntegerAttribute:
		{
			std::stringstream str;
			str << dynamic_cast< const IntAttrItem* >( &item )->_value;
			return str.str();
		}
		case kOMFStringAttribute:
			return dynamic_cast< const StringAttrItem* >( &item )->_value;
		case kOMFObjectAttribute:
			return "<object>";
		case kOMFBobAttribute:
			return "<bob>";
	}

    TR_TRACE( "Unknown AAttrList item type (" << item._type << ") encountered." );
    
	return "<unknown>";
}

void AAttrList::writeToStream( AStream& str ) const
{
	str.writePod< UInt8 >( 0x02 );
	str.writePod< UInt8 >( 0x01 );

	// TODO: Implement
}

void AAttrList::readFromStream( AStream& str, const AObjDoc& objd )
{
	UInt8 v1, v2;

	str.readPod( v1 );
	str.readPod( v2 );

	// Version must be 0x02 0x03
	TR_ASSERT( v1 == 0x02 );
	TR_ASSERT( v2 == 0x01 );

	// Read the number of attributes
	UInt32 numAttrs;
	str.readPod( numAttrs );

	// TR_TRACE( "AAttrList::readFromStream: Reading " << numAttrs << " attributes..." );

	for( unsigned int i = 0; i < numAttrs; ++i )
	{
		// Read the attribute type field
		UInt32 attrType;
		str.readPod( attrType );

		// Read the attribute name
		std::string attrName = str.readString();

		// Read the attribute value
		switch( attrType )
		{
			case kOMFNullAttribute:
			{
				// TODO: How do we deal with this?!
				TR_TRACE( "Don't know how to deal with NULL attributes :(" );
				break;
			}

			case kOMFIntegerAttribute:
			{
				Int32 val;
				str.readPod( val );
				_items[ attrName ] = new IntAttrItem( val );
				break;
			}

			case kOMFStringAttribute:
			{
				std::string val = str.readString();
				_items[ attrName ] = new StringAttrItem( val );
				break;
			}

			case kOMFObjectAttribute:
			{
				UInt32 val;
				str.readPod( val );

				// Find convert the reference from the file into a pointer
				AObject* obj = objd.resolveRef< AObject >( val );

				_items[ attrName ] = new ObjectAttrItem( obj );
				break;
			}

			default:
			{
				TR_TRACE( "Invalid attribut type " << attrType );
				throw "Invalid attribute type";
			}
		}
	}

	UInt8 tagMarkerEnd;
	str.readPod( tagMarkerEnd );
	TR_ASSERT( tagMarkerEnd == 0x03 );
}

static std::string attrTypeToStr( AAttrList::AttrType type )
{
	switch( type )
	{
		case AAttrList::kOMFNullAttribute: return "kOMFNullAttribute";
		case AAttrList::kOMFIntegerAttribute: return "kOMFIntegerAttribute";
		case AAttrList::kOMFStringAttribute: return "kOMFStringAttribute";
		case AAttrList::kOMFObjectAttribute: return "kOMFObjectAttribute";
	}

	std::stringstream str;

	str << "<undefined:" << type << ">";
	return str.str();
}

void AAttrList::dump( std::ostream& str ) const
{
	str << "AAttrList {" << std::endl;
	str << "\t_items[ " << _items.size() << " ] {" << std::endl;

	AttrMap::const_iterator it = _items.begin();

	for( ; it != _items.end(); ++it ) {
		str << "\t\tAttrItem {" << std::endl;
		str << "\t\t\t_name: "  << it->first << std::endl;
		str << "\t\t\t_type: "  << attrTypeToStr( it->second->_type ) << std::endl;
		str << "\t\t\t_value: " << getAttrAsString( *(it->second) ) << std::endl;
		str << "\t\t}" << std::endl;
	}

	str << "\t}" << std::endl;
	str << "}" << std::endl;
}
